﻿using System;
using UnityEngine.Animations;
#if LOCK_STEP
using FLOAT = SoftFloat.sfloat;
#else
using FLOAT = System.Single;
#endif

namespace GameDesigner
{
    /// <summary>
    /// ARPG状态动作
    /// </summary>
	[Serializable]
    public sealed class StateAction : StateBase
    {
        /// <summary>
        /// 动画剪辑名称
        /// </summary>
		public string clipName;
        /// <summary>
        /// 动画剪辑长度
        /// </summary>
        public FLOAT length;
        /// <summary>
        /// 动画剪辑资源 --可是可播放动画资源, 也可以是动画剪辑或其他
        /// </summary>
        public UnityEngine.Object clipAsset;
        /// <summary>
        /// 当前动画时间
        /// </summary>
		public FLOAT animTime;
        /// <summary>
        /// 动画结束时间
        /// </summary>
		public FLOAT animTimeMax = 100f;
        private bool isStop;
        /// <summary>
        /// 动作是否完成?, 当动画播放结束后为True, 否则为false
        /// </summary>
        public bool IsComplete => animTime >= animTimeMax - 1;

        /// <summary>
        /// 如果动画是混合树，该参数则为混合树的1D参数值
        /// </summary>
        public float blendParameter;
        /// <summary>
        /// 如果动画是混合树，该参数则为混合树的1D参数名称
        /// </summary>
        public string blendParameterName;
        /// <summary>
        /// 如果动画是混合树,该参数为混合树的2D参数名称
        /// </summary>
        public string blendParameterYName;
        /// <summary>
        /// 如果动画是混合树，该参数则为混合树的2D参数值
        /// </summary>
        public float blendParameterY;
        /// <summary>
        /// 使用状态机来控制混合树的动画播放，如果为True，则使用状态机控制参数，否则使用Unity的Animator控制参数, 默认为False
        /// </summary>
        public bool useStateMachineForBlendTree = false;
        public int inputIndex;

        /// <summary>
        /// 当前状态
        /// </summary>
        public State state => stateMachine.States[Id];

        public int GetActionIndex()
        {
            for (int i = 0; i < state.actions.Length; i++)
            {
                if (state.actions[i] == this)
                    return i;
            }
            return -1;
        }

        public StateAction() { }

        public StateAction(State state, string clipName, params ActionBehaviour[] behaviours)
        {
            Id = state.Id;
            SetAnimClip(clipName);
            if (behaviours != null)
                AddComponent(behaviours);
            else this.behaviours = new ActionBehaviour[0];
            ArrayHelper.Add(ref state.actions, this);
        }

        internal void Enter(State state)
        {
            isStop = false;
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as ActionBehaviour;
                if (behaviour.Active)
                    behaviour.OnEnter();
            }
            stateMachine.Handler.OnPlayAnimation(state, this);
        }

        internal void Exit()
        {
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as ActionBehaviour;
                if (behaviour.Active)
                    behaviour.OnExit();
            }
            stateMachine.Handler.OnAnimationEnd(state, this);
        }

        internal void Init(IStateMachine stateMachine, params object[] args)
        {
            this.stateMachine = stateMachine;
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = (ActionBehaviour)behaviours[i].InitBehaviour(stateMachine);
                behaviour.Action = this;
                behaviours[i] = behaviour;
                behaviour.OnInit(args);
            }
        }

        internal void Update(State state, StateMachineUpdateMode currMode)
        {
            if (isStop)
                return;
            var isPlaying = stateMachine.Handler.OnAnimationUpdate(state, this, currMode);
            for (int i = 0; i < behaviours.Length; i++)
            {
                var behaviour = behaviours[i] as ActionBehaviour;
                if (behaviour.Active)
                {
                    switch (currMode)
                    {
                        case StateMachineUpdateMode.Update:
                            behaviour.OnUpdate();
                            break;
                        case StateMachineUpdateMode.LateUpdate:
                            behaviour.OnLateUpdate();
                            break;
                        case StateMachineUpdateMode.FixedUpdate:
                            behaviour.OnFixedUpdate();
                            break;
                    }
                }
            }
            if (animTime >= animTimeMax || !isPlaying)
            {
                stateMachine.Handler.OnAnimationEnd(state, this);
                if (state.isExitState & state.transitions.Length > 0)
                {
                    state.transitions[state.dstStateID].isEnterNextState = true;
                    return;
                }
                if (state.animLoop)
                {
                    for (int i = 0; i < behaviours.Length; i++)
                    {
                        var behaviour = behaviours[i] as ActionBehaviour;
                        if (behaviour.Active)
                            behaviour.OnExit();
                    }
                    state.OnActionExit();
                    if (stateMachine.NextId == state.Id)//如果在动作行为里面有切换状态代码, 则不需要重载函数了, 否则重载当前状态
                        state.Enter(-1, state.actionIndex, false);//重载进入函数
                }
                else
                {
                    isStop = true;
                    for (int i = 0; i < behaviours.Length; i++)
                    {
                        var behaviour = behaviours[i] as ActionBehaviour;
                        if (behaviour.Active)
                            behaviour.OnStop();
                    }
                    state.OnActionStop();
                }
            }
        }

        public void SetAnimClip(string clipName)
        {
            this.clipName = clipName;
        }

        public static void SetBlendTreeParameter(StateAction stateAction, UnityEngine.Animator animator)
        {
            if (!string.IsNullOrEmpty(stateAction.blendParameterName) && stateAction.useStateMachineForBlendTree)
                animator.SetFloat(stateAction.blendParameterName, stateAction.blendParameter);

            if (!string.IsNullOrEmpty(stateAction.blendParameterYName) && stateAction.useStateMachineForBlendTree)
                animator.SetFloat(stateAction.blendParameterYName, stateAction.blendParameterY);
        }
    }
}